//
// Created by mio on 25-5-16.
//

#include "AVPlayer.h"

#include <qevent.h>

#include "EventLoop.h"
#include "../UI/tool/define.h"
#include "../Net/SigConnection.h"

Q_DECLARE_METATYPE(AVFramePtr)

AVPlayer::AVPlayer(EventLoop *loop, QWidget *parent) : OpenGLRender(parent), loop_(loop)
{
    setFocus();
    // 设置窗口属性
    this->resize(800, 500);
    // 设置无边框
    this->setWindowFlags(Qt::FramelessWindowHint);
    // 背景颜色
    this->setAttribute(Qt::WA_StyledBackground);
    Init();
}

AVPlayer::~AVPlayer()
{
    Close();
}

void AVPlayer::Init()
{
    avContext_ = new AVContext();
    avDEMuxer_.reset(new AVDEMuxer(avContext_));
    this->InitAudio(2, 44100, 16);
    connect(this, &AVPlayer::sig_repaint, this, &OpenGLRender::Repaint, Qt::QueuedConnection);
}

void AVPlayer::Close()
{
    stop_ = true;
    if (audioThread_->joinable())
    {
        audioThread_->join();
        audioThread_.reset();
        audioThread_ = nullptr;
    }
    if (videoThread_->joinable())
    {
        videoThread_->join();
        videoThread_.reset();
        videoThread_ = nullptr;
    }
    if (avDEMuxer_)
    {
        avDEMuxer_.reset();
        avDEMuxer_ = nullptr;
    }
}

bool AVPlayer::Connect(QString ip, uint16_t port, QString code)
{
    TcpSocket socket;
    socket.Create();
    if (!socket.Connect(ip.toStdString(), port)) {
        qDebug() << "connect failed";
        return false;
    }
    qDebug() << "AVPlayer连接信令服务器成功";
    // 生成一个信令连接器
    sig_conn_.reset(new SigConnection(loop_->GetTaskScheduler().get(),
        socket.GetSocket(), code, SigConnection::CONTROLLING)); // 控制端
    sig_conn_->SetStopStreamCallBack([this]() {
        this->HandleStopStream();
    });
    sig_conn_->SetStartStreamCallBack([this](const QString& streamAddr) {
        return this->HandleStartStream(streamAddr);
    });
    return true;
}

void AVPlayer::AudioPlay()
{
    AVFramePtr frame = nullptr;
    while (!stop_ && avDEMuxer_ && avContext_) {
        if (!AvailableBytes() || avContext_->audio_queue_.empty())
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            continue;
        }
        avContext_->audio_queue_.pop(frame);
        Write(frame);
    }
}

void AVPlayer::VideoPlay()
{
    AVFramePtr frame = nullptr;
    while (!stop_ && avDEMuxer_ && avContext_)
    {
        if (avContext_->video_queue_.empty())
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            continue;
        }
        avContext_->video_queue_.pop(frame);
        sig_repaint(frame);
    }
}

void AVPlayer::resizeEvent(QResizeEvent *event) {
    OpenGLRender::resizeEvent(event);
}

void AVPlayer::wheelEvent(QWheelEvent *event)
{
    if (!sig_conn_->IsClosed()) {
        Wheel_Body body;
        body.wheel = event->Wheel;
        QPoint pixelDelta = event->pixelDelta();
        QPoint angleDelta = event->angleDelta();
        body.wheel = (!pixelDelta.isNull() ? (pixelDelta.y() > 0 ? 1 : -1) : (angleDelta.y() > 0 ? 1 : -1));
        sig_conn_->Send((const char*)&body, body.len);
    }
    QWidget::wheelEvent(event);
}

void AVPlayer::mouseMoveEvent(QMouseEvent *event)
{
    if(!sig_conn_->IsClosed())
    {
        MouseMove_Body body;
        //获取这个x,y比值，后面实现
        this->GetPosRation(body);
        sig_conn_->Send((const char*)&body,body.len);
    }
    QWidget::mouseMoveEvent(event);
}

void AVPlayer::mousePressEvent(QMouseEvent *event)
{
    if(!sig_conn_->IsClosed())
    {
        Mouse_Body body;
        body.type = MouseKeyType::PRESS;
        body.mouseButtons = (MouseType)event->button(); // 与Qt的枚举值对应
        sig_conn_->Send((const char*)&body,body.len);
    }
    QWidget::mousePressEvent(event);
}

void AVPlayer::mouseReleaseEvent(QMouseEvent *event)
{
    if(!sig_conn_->IsClosed())
    {
        Mouse_Body body;
        body.type = MouseKeyType::RELEASE;
        body.mouseButtons = (MouseType)event->button();
        sig_conn_->Send((const char*)&body,body.len);
    }
    QWidget::mouseReleaseEvent(event);
}

void AVPlayer::keyPressEvent(QKeyEvent *event)
{
    if(!sig_conn_->IsClosed())
    {
        Key_Body body;
        body.type = MouseKeyType::PRESS;
        body.key = event->key();
        sig_conn_->Send((const char*)&body,body.len);
    }
    QWidget::keyPressEvent(event);
}

void AVPlayer::keyReleaseEvent(QKeyEvent *event)
{
    if(!sig_conn_->IsClosed())
    {
        Key_Body body;
        body.type = MouseKeyType::RELEASE;
        body.key = event->key();
        sig_conn_->Send((const char*)&body,body.len);
    }
    QWidget::keyReleaseEvent(event);
}

void AVPlayer::HandleStopStream()
{
    // 停止拉流
    Close();
}

bool AVPlayer::HandleStartStream(const QString &streamAddr)
{
    // 开始拉流
    avDEMuxer_->Open(streamAddr.toStdString().c_str());

    audioThread_.reset(new std::thread([this]() {
        this->AudioPlay();
    }));

    videoThread_.reset(new std::thread([this]() {
        this->VideoPlay();
    }));

    return true;
}
